#include <ximera/audio/openal/sound.hpp>
#include <ximera/logger.hpp>

namespace ximera { namespace audio { namespace openal
{
    Sound::Sound()
    {
        alGenSources(1, &_source);
        openal::checkErrorAndThrow(L"Error generating source");

        ALfloat posvel[] = {0,0,0};
        ALfloat ori[] = {0,0,-1, 0,1,0};

        alSourcefv(_source, AL_POSITION, posvel);
        alSourcefv(_source, AL_VELOCITY, posvel);
        alSourcefv(_source, AL_DIRECTION, ori);
    }

    Sound::~Sound()
    {
        alDeleteSources(1, &_source);
    }

    SharedPtr<ISoundData> const& Sound::soundData() const
    {
        return _soundData;
    }

    void Sound::soundData(SharedPtr<ISoundData> const& data)
    {
        _soundData.reset();

        if (SoundData* alData = dynamic_cast<SoundData*>(data.get()))
        {
            alSourcei(_source, AL_BUFFER, alData->buffer());
            openal::checkErrorAndThrow(L"Error linking source data");

            _soundData = data;
        }
    }

    void Sound::soundData(ISoundData* data)
    {
        _soundData.reset();

        if (SoundData* alData = dynamic_cast<SoundData*>(data))
        {
            alSourcei(_source, AL_BUFFER, alData->buffer());
            openal::checkErrorAndThrow(L"Error linking source data");

            _soundData.reset(data);
        }
    }

    math::Vector3 Sound::position() const
    {
        return _position;
    }

    void Sound::position(math::Vector3 const& pos)
    {
        _position = pos;

        alSourcefv(_source, AL_POSITION, _position.array());
    }

    math::Vector3 Sound::velocity() const
    {
        return _velocity;
    }

    void Sound::velocity(math::Vector3 const& vel)
    {
        _velocity = vel;

        alSourcefv(_source, AL_VELOCITY, _velocity.array());
    }

    LoopMode Sound::loopMode() const
    {
        ALint mode;
        alGetSourcei(_source, AL_LOOPING, &mode);
        return (mode == AL_TRUE) ? LoopMode::On : LoopMode::Off;
    }

    void Sound::loopMode(LoopMode mode)
    {
        alSourcei(_source, AL_LOOPING, (mode == LoopMode::On) ? AL_TRUE : AL_FALSE);
    }

    void Sound::play()
    {
        alSourcePlay(_source);
    }

    void Sound::stop()
    {
        alSourceStop(_source);
    }

    void Sound::pause()
    {
        alSourcePause(_source);
    }
}}}